#!/usr/bin/env python

import wx
from hostsfile import HostsFile

class HostsRootFrame(wx.Frame):
    allowedFiles = "Hosts Files (hosts)|hosts|All Files (*)|*"
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title, wx.DefaultPosition, size=(800, 600))

        self.hostsFile = HostsFile()
       
        self.setupMenu()
        self.setupToolbar()

        self.rootSizer = wx.BoxSizer(wx.VERTICAL)
        self.rootPanel = wx.Panel(self, -1)
        
        self.mainSizer = wx.BoxSizer(wx.HORIZONTAL)
        
        self.setupList()
        self.setupEditArea()

        self.rootPanel.SetSizer(self.mainSizer)
        self.rootSizer.Add(self.rootPanel, 1, wx.EXPAND)

        self.SetSizer(self.rootSizer)
       
        self.Center()
        self.Show(True)

    def iconedMenuItem(self, menu, id, label, hover, image):
        menuItem = wx.MenuItem(menu, id, label, hover)
        menuItem.SetBitmap(wx.Bitmap(image))
        return menuItem

    def setupMenu(self):
        menubar = wx.MenuBar()

        fileMenu = wx.Menu()

        fileMenu.AppendItem(self.iconedMenuItem(fileMenu, 101, '&New\tCtrl+N', 'Create a new alernate hosts file', 'icons/16/new.png'))
        fileMenu.AppendItem(self.iconedMenuItem(fileMenu, 102, '&Open\tCtrl+O', 'Open an alernate hosts file', 'icons/16/open.png'))
        fileMenu.AppendItem(self.iconedMenuItem(fileMenu, 103, '&Save\tCtrl+S', 'Save the current hosts file', 'icons/16/save.png'))
        fileMenu.AppendItem(self.iconedMenuItem(fileMenu, 104, 'Save &As\tCtrl+Shift+S', 'Save the current hosts file to an alternate location', 'icons/16/save_as.png'))
        fileMenu.AppendSeparator()
        fileMenu.AppendItem(self.iconedMenuItem(fileMenu, 105, '&Quit\tCtrl+Q', 'Quit the Application', 'icons/16/quit.png'))

        self.Bind(wx.EVT_MENU, self.OnNew, id=101)
        self.Bind(wx.EVT_MENU, self.OnOpen, id=102)
        self.Bind(wx.EVT_MENU, self.OnSave, id=103)
        self.Bind(wx.EVT_MENU, self.OnSaveAs, id=104)
        self.Bind(wx.EVT_MENU, self.OnQuit, id=105)

        editMenu = wx.Menu()
        editMenu.AppendItem(self.iconedMenuItem(editMenu, 201, '&Copy\tCtrl+C', 'Open an alernate hosts file', 'icons/16/copy.png'))
        editMenu.AppendItem(self.iconedMenuItem(editMenu, 202, 'C&ut\tCtrl+X', 'Copy Selected Item and remove', 'icons/16/cut.png'))
        editMenu.AppendItem(self.iconedMenuItem(editMenu, 203, '&Paste\tCtrl+V', 'Paste item currently in the clipboard', 'icons/16/paste.png'))

        self.Bind(wx.EVT_MENU, self.OnCopy, id=201)
        self.Bind(wx.EVT_MENU, self.OnCut, id=202)
        self.Bind(wx.EVT_MENU, self.OnPaste, id=203)
        
        helpMenu = wx.Menu()
        helpMenu.Append(301, '&About', 'Information About this application.')

        self.Bind(wx.EVT_MENU, self.OnAbout, id=301)

        menubar.Append(fileMenu, '&File')
        menubar.Append(editMenu, '&Edit')
        menubar.Append(helpMenu, '&Help')

        self.SetMenuBar(menubar)
        self.CreateStatusBar()

    def setupToolbar(self):
        toolbar = self.CreateToolBar()

        toolbar.AddLabelTool(102, '', wx.Bitmap('icons/16/open.png'))
        toolbar.AddLabelTool(103, '', wx.Bitmap('icons/16/save.png'))
        toolbar.AddLabelTool(104, '', wx.Bitmap('icons/16/save_as.png'))
        toolbar.AddSeparator()

        toolbar.AddLabelTool(201, '', wx.Bitmap('icons/16/copy.png'))
        toolbar.AddLabelTool(202, '', wx.Bitmap('icons/16/cut.png'))
        toolbar.AddLabelTool(202, '', wx.Bitmap('icons/16/paste.png'))
        
        toolbar.Realize()

    def setupList(self):
        addressPanel = wx.Panel(self.rootPanel, -1)
        addressSizer = wx.BoxSizer(wx.VERTICAL)

        self.addressList = wx.ListBox(addressPanel, 1100, (-1,-1), (-1,-1), self.hostsFile.getAddresses(), wx.LB_SORT | wx.LB_SINGLE)
        self.Bind(wx.EVT_LISTBOX, self.OnLoadHosts, id=1100)

        addressSizer.Add(self.addressList, 1, wx.EXPAND | wx.ALL, 10)

        btnAddressPanel = wx.Panel(addressPanel, -1)
        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
        new    = wx.Button(btnAddressPanel, 1101, 'New', size=(90,30))
        edit   = wx.Button(btnAddressPanel, 1102, 'Edit', size=(90,30))
        delete = wx.Button(btnAddressPanel, 1103, 'Delete', size=(90,30))

        self.Bind(wx.EVT_BUTTON, self.OnAddressNew, id=1101)
        self.Bind(wx.EVT_BUTTON, self.OnAddressEdit, id=1102)
        self.Bind(wx.EVT_BUTTON, self.OnAddressDelete, id=1103)
        
        btnSizer.Add(new, 0, wx.LEFT, 10)
        btnSizer.Add(edit)
        btnSizer.Add(delete, 0, wx.RIGHT, 10)
        btnAddressPanel.SetSizer(btnSizer)
        
        addressSizer.Add(btnAddressPanel, 0.6, wx.EXPAND | wx.BOTTOM, 10)
        addressPanel.SetSizer(addressSizer)
                
        self.mainSizer.Add(addressPanel, 0.4, wx.EXPAND)

    def setupEditArea(self):
        editPanel = wx.Panel(self.rootPanel, -1)
        editSizer = wx.BoxSizer(wx.VERTICAL)

        self.hostsList = wx.ListBox(editPanel, -1, (-1,-1), (-1,-1), [], wx.LB_SORT | wx.LB_MULTIPLE)
        
        editSizer.Add(self.hostsList, 1, wx.EXPAND | wx.ALL, 10)

        btnEditPanel = wx.Panel(editPanel, -1)
        btnEditSizer = wx.BoxSizer(wx.HORIZONTAL)
        new      = wx.Button(btnEditPanel, 2101, 'New', size=(90,30))
        edit     = wx.Button(btnEditPanel, 2102, 'Edit', size=(90,30))
        delete   = wx.Button(btnEditPanel, 2103, 'Delete', size=(90,30))

        self.Bind(wx.EVT_BUTTON, self.OnHostNew, id=2101)
        self.Bind(wx.EVT_BUTTON, self.OnHostEdit, id=2102)
        self.Bind(wx.EVT_BUTTON, self.OnHostDelete, id=2103)

        btnEditSizer.Add(new, 0, wx.LEFT, 10)
        btnEditSizer.Add(edit)
        btnEditSizer.Add(delete, 0, wx.RIGHT, 10)
        btnEditPanel.SetSizer(btnEditSizer)

        editSizer.Add(btnEditPanel, 0.6, wx.EXPAND | wx.BOTTOM, 10)
        editPanel.SetSizer(editSizer)

        self.mainSizer.Add(editPanel, 1, wx.EXPAND)

    def ShowSaveDialog(self):
        saveDialog = wx.FileDialog(None, message="Save...", defaultDir=HostsFile.getHostsPath(), defaultFile="hosts", style=wx.SAVE | wx.FD_OVERWRITE_PROMPT)

        if saveDialog.ShowModal() == wx.ID_OK:
            filename = saveDialog.GetPath()
            return filename
            saveDialog.Destroy()
        return False

    def ReloadAddresses(self):
        self.addressList.SetItems(self.hostsFile.getAddresses())
        self.hostsList.SetItems([])
        self.currentAddress = None

    def OnLoadHosts(self, event):
        selected = self.addressList.GetSelection()
        if selected >= 0:        
            address  = self.addressList.GetString(selected)
            items    = self.hostsFile.getHostsFor(address)

            self.hostsList.SetItems(items)
            self.currentAddress = address

    def OnHostNew(self, event):
        if self.currentAddress == None:
            return False
        newHost = wx.GetTextFromUser('Host', 'New Host', '')
        if newHost == '':
            return False
        while self.hostsFile.checkHostExists(newHost):
            error = 'Error: The specified host already exists'
            newHost = wx.GetTextFromUser('Host\n%s' % error, 'Edit Host', newHost)
            if newHost == '':
                return False
        if(self.hostsFile.newHost(self.currentAddress, newHost)):
           self.hostsList.Append(newHost)
            
    def OnHostEdit(self, event):
        if self.currentAddress == None:
            return False
        
        selected = self.hostsList.GetSelections()
        for host in selected:
            newHost = wx.GetTextFromUser('Host', 'Edit Host', self.hostsList.GetString(host))
            if newHost == '':
                return False
            while self.hostsFile.checkHostExists(newHost):
                error = 'Error: The specified host already exists'
                newHost = wx.GetTextFromUser('Host\n%s' % error, 'Edit Host', newHost)
                if newHost == '':
                    return False
                
            if self.hostsFile.replaceHost(self.currentAddress, self.hostsList.GetString(host), newHost):
                self.hostsList.SetString(host, newHost)

    def OnHostDelete(self, event):
        if self.currentAddress == None:
            return False

        selected = self.hostsList.GetSelections()
        if len(selected) > 0:
            conf = wx.MessageDialog(None, 'Are you sure wish to remove %d host(s)?' % len(selected), 'Delete Hosts?', wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
            if conf.ShowModal() != wx.ID_YES:
                return False

        while len(selected) > 0:
            host = selected[0]
            if self.hostsFile.removeHost(self.currentAddress, self.hostsList.GetString(host)):
                self.hostsList.Delete(host)
            elif not self.hostsFile.checkHostExists(self.hostsList.GetString(host)):
                self.hostsList.Delete(host)
            selected = self.hostsList.GetSelections()

    def OnAddressNew(self, event):
        newAddress = wx.GetTextFromUser('Address', 'New Address', '')
        if newAddress == '':
            return False
        while self.hostsFile.checkAddressExists(newAddress):
            error = 'Error: The specified address already exists'
            newAddress = wx.GetTextFromUser('Address\n%s' % error, 'Edit Address', newHost)
            if newAddress == '':
                return False
        if(self.hostsFile.newAddress(newAddress)):
           self.addressList.Append(newAddress)
           self.addressList.SetSelection(self.addressList.GetItems().index(newAddress))
           self.OnLoadHosts(event)

    def OnAddressEdit(self, event):
        selected = self.addressList.GetSelection()

        if selected >= 0:
            newAddress = wx.GetTextFromUser('Address', 'Edit Address', self.addressList.GetString(selected))
            if newAddress == '':
                return False
            while self.hostsFile.checkAddressExists(newAddress):
                error = 'Error: The specified address already exists'
                newAddress = wx.GetTextFromUser('Address\n%s' % error, 'Edit Address', self.addressList.GetString(selected), )
                if newAddress == '':
                    return False
            if(self.hostsFile.replaceAddress(self.addressList.GetString(selected), newAddress)):
               self.ReloadAddresses()
               self.addressList.SetSelection(self.addressList.GetItems().index(newAddress))
               self.OnLoadHosts(event)

    def OnAddressDelete(self, event):
        selected = self.addressList.GetSelection()
        if selected >= 0:
            conf = wx.MessageDialog(None, 'Are you sure wish to remove this address.', 'Delete Address?', wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
            if conf.ShowModal() != wx.ID_YES:
                return False

            if self.hostsFile.removeAddress(self.addressList.GetString(selected)):
                self.addressList.Delete(selected)
                self.ReloadAddresses()
            elif not self.hostsFile.checkAddressExists(self.addressList.GetString(selected)):
                self.addressList.Delete(selected)
                self.ReloadAddresses()

    def OnNew(self, event):
        filename = self.ShowSaveDialog()
        self.hostsFile = HostsFile(filename)
        self.ReloadAddresses()

    def OnOpen(self, event):
        openDialog = wx.FileDialog(None, message="Open...", defaultDir=HostsFile.getHostsPath(), defaultFile="hosts", style=wx.OPEN)

        if openDialog.ShowModal() == wx.ID_OK:
            filename = openDialog.GetPath()
            openDialog.Destroy()
            self.hostsFile = HostsFile(filename)
            self.ReloadAddresses()

    def OnSave(self, event):
        self.hostsFile.save()
        self.ReloadAddresses()

    def OnSaveAs(self, event):
        filename = self.ShowSaveDialog()
        self.hostsFile.save(filename)
        self.ReloadAddresses()

    def OnCopy(self, event):
        pass

    def OnCut(self, event):
        pass

    def OnPaste(self, event):
        pass

    def OnAbout(self, event):
        description = """Edit hosts is a simple application for managing large 'hosts' files.

Hosts file are system resources used as part of the DNS lookup process.
As these files are check first, they provide a useful way of overriding DNS enteries.
"""
        licence = """Edit hosts is free software; you can redistribute it and/or modify it 
under the terms of the GNU General Public License as published by the Free Software Foundation; 
using version 2 of the License Only.

Edit hosts is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; 
without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
See the GNU General Public License for more details. You should have received a copy of 
the GNU General Public License along with File Hunter; if not, write to 
the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA"""

        info = wx.AboutDialogInfo()
        info.SetName('Edit Hosts')
        info.SetVersion('0.9.0')
        info.SetDescription(description)
        info.SetCopyright('(C) 2008 Nicholas Steicke')
        info.SetLicence(licence)
        info.AddDeveloper('Nicholas Steicke')
        info.AddArtist('FamFamFam Silk Icon Set - http://www.famfamfam.com/lab/icons/silk/')

        wx.AboutBox(info)

    def OnQuit(self, event):
        self.Close()

class HostsApp(wx.App):
    def OnInit(self):
        frame = HostsRootFrame(None, -1, 'Edits Hosts')
        frame.Show(True)
        return True
    
def main():
    app = HostsApp()
    app.MainLoop()

if __name__ == '__main__':
    main();
